package com.design.pattern.prototype.managers;

import java.io.*;
import java.util.Hashtable;
/**
 * 钱
 */
interface Money<T extends Money> extends Cloneable{
    /**
     * 浅copy
     * @return
     */
    public T clone();

    /**
     * 深copy
     * @return
     */
    public T deepClone();
}

/**
 * RMB
 */
class RMB implements Money<RMB>{


    /**
     * 浅copy
     *
     * @return
     */
    @Override
    public RMB clone()   {
        RMB rmb=null;
        try {
            rmb=(RMB)super.clone();
        }catch (CloneNotSupportedException e) {
            e.printStackTrace();
        }
        return  rmb;
    }

    /**
     * 深copy
     *
     * @return
     */
    @Override
    public RMB deepClone() {
        RMB rmb=null;
        try(
                ByteArrayOutputStream bos=new ByteArrayOutputStream();
                ObjectOutputStream oos=new ObjectOutputStream(bos);
                ByteArrayInputStream bis=new ByteArrayInputStream(bos.toByteArray());
                ObjectInputStream ois=new ObjectInputStream(bis);
                ){
                oos.writeObject(this);
            rmb= (RMB) ois.readObject();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
        return rmb;
    }
}
class Dollar implements Money<Dollar>{

    /**
     * 浅copy
     *
     * @return
     */
    @Override
    public Dollar clone() {
        Dollar dollar=null;
        try {
            dollar= (Dollar) super.clone();
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
        }
        return dollar;
    }

    /**
     * 深copy
     *
     * @return
     */
    @Override
    public Dollar deepClone() {
        Dollar dollar=null;
        try(
                ByteArrayOutputStream bos=new ByteArrayOutputStream();
                ObjectOutputStream oos=new ObjectOutputStream(bos);
                ByteArrayInputStream bis=new ByteArrayInputStream(bos.toByteArray());
                ObjectInputStream ois=new ObjectInputStream(bis);
                ){
            oos.writeObject(this);
            dollar= (Dollar) ois.readObject();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
        return dollar;
    }
}
/**
 * 原型管理器(单例)
 */
public class PrototypeManagers {
    /**
     * 禁用指令重排序[volatile]
     */
    private static  volatile PrototypeManagers instance=null;

    /**
     * 双重检查锁
     * @return
     */
    public static PrototypeManagers getInstance(){
        if (null==instance){
            synchronized (PrototypeManagers.class){
                if (null==instance){
                    instance=new PrototypeManagers();
                }
            }
        }
        return instance;
    }
    /**
     * 存放原型管理器实例
     */
    private Hashtable<String,Money> prototypeTable=new Hashtable();

    /**
     * 获取原型实例
     * @param key
     * @return
     */
    public Money getPrototype(String key) {
        return prototypeTable.get(key);
    }

    /**
     * 设置原型实例
     * @param key
     * @param value
     */
    public void setPrototype(String key,Money value) {
        this.prototypeTable.put(key,value);
    }
}
